#include "TKSPStdAfx.h"

#include "DBXDeviceFactory.h"

namespace DBX
{
    static std::list<DBXDeviceFactory *> g_deviceFactories;

    class DBXDeviceFactory::Private
    {
    public:
        Private(DBXDeviceFactory *pOwner, const std::string &devType)
            : o(pOwner)
            , m_devType(devType)
        {
            g_deviceFactories.emplace_back(o);
        }

        ~Private()
        {
            g_deviceFactories.remove(o);
        }

        bool canCreate() const
        {
            return bool(m_creator);
        }

        std::shared_ptr<DBXDevice> create() const
        {
            if (!m_creator) {
                return std::shared_ptr<DBXDevice>();
            }

            return m_creator();
        }

    private:
        friend class DBXDeviceFactory;
        DBXDeviceFactory *o;
        const std::string m_devType;
        std::string m_displayName;
        std::function<std::shared_ptr<DBXDevice>()> m_creator;
    };

    DBXDeviceFactory::DBXDeviceFactory(const std::string &devType)
        : p(*new Private(this, devType))
    {
    }

    void DBXDeviceFactory::setDisplayName(const std::string &displayName)
    {
        p.m_displayName = displayName;
    }

    void DBXDeviceFactory::setCreator(const std::function<std::shared_ptr<DBXDevice>()> &creator)
    {
        p.m_creator = creator;
    }

    DBXDeviceFactory::~DBXDeviceFactory()
    {
        delete &p;
    }

    std::string DBXDeviceFactory::deviceType() const
    {
        return p.m_devType;
    }

    std::string DBXDeviceFactory::displayName() const
    {
        return p.m_displayName;
    }

    bool DBXDeviceFactory::canCreate() const
    {
        return bool(p.m_creator);
    }

    std::shared_ptr<DBXDevice> DBXDeviceFactory::create() const
    {
        return p.create();
    }

    const std::list<DBXDeviceFactory *> DBXDeviceFactory::allDeviceFactories()
    {
        return g_deviceFactories;
    }

    DBXDeviceFactory *DBXDeviceFactory::find(const std::string &devType)
    {
        for (auto &f : g_deviceFactories) {
            if (f->deviceType() == devType) {
                return f;
            }
        }
        return nullptr;
    }
} // namespace DBX